package com.cy.ppj.service.order.impl;

import com.alibaba.fastjson.JSON;
import com.cy.ppj.comm.third.tg.Cryptor;
import com.cy.ppj.comm.third.tg.HttpClientUtil;
import com.cy.ppj.dao.mapper.order.OrderMapper;
import com.cy.ppj.dao.mapper.order.OrderWithholdMapper;
import com.cy.ppj.dao.mapper.order.WithholdRecordMapper;
import com.cy.ppj.dao.mongodb.MongoDao;
import com.cy.ppj.dao.mongodb.WithholdLogDao;
import com.cy.ppj.dao.mongodb.WithholdQueryLogDao;
import com.cy.ppj.model.Result;
import com.cy.ppj.model.doc.WithholdLog;
import com.cy.ppj.model.doc.WithholdQueryLog;
import com.cy.ppj.model.domian.order.Order;
import com.cy.ppj.model.domian.order.OrderWithhold;
import com.cy.ppj.model.domian.order.WithholdRecord;
import com.cy.ppj.model.enums.UniqueKeyType;
import com.cy.ppj.model.enums.WithholdStatus;
import com.cy.ppj.service.BaseService;
import com.cy.ppj.service.comm.UniqueKeyService;
import com.cy.ppj.service.order.WithholdRecordService;
import com.cy.ppj.service.order.WithholdService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @description: 代扣
 * @author: Ocean
 * @create: 2018-07-24 15:28
 **/
@Slf4j
@Service
public class TGWithholdServiceImpl extends BaseService implements WithholdService {

    /**
     * 请求地址
     */
    @Value("${withhold.tg.http-url}")
    private String httpUrl;
    /**
     * 企业号
     */
    @Value("${withhold.tg.corp-no}")
    private String corpNo;
    /**
     * 密码
     */
    @Value("${withhold.tg.password}")
    private String password;
    /**
     * 文件地址
     */
    @Value("${withhold.tg.file-path}")
    private String filePath;

    @Autowired
    private OrderWithholdMapper orderWithholdMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private WithholdLogDao withholdLogDao;
    @Autowired
    private WithholdQueryLogDao withholdQueryLogDao;
    @Autowired
    private MongoDao mongoDao;
    @Autowired
    private UniqueKeyService uniqueKeyService;
    @Autowired
    private WithholdRecordService withholdRecordService;
    @Autowired
    private WithholdRecordMapper withholdRecordMapper;

    @Override
    public Result withholding(Long orderId, Long managerId) {

        try {
            boolean isExist = uniqueKeyService.isExist(UniqueKeyType.WITHHOLD, String.valueOf(orderId));
            WithholdLog withholdLog = null;
            //有历史记录则查询
            if (isExist) {
                //查找处理中的记录
                WithholdRecord withholdRecord = withholdRecordMapper.selectProcessingByOrderId(orderId);
                //通过记录查找代扣日志，进行查询
                withholdLog = withholdLogDao.findByWithholdRecordId(withholdRecord.getId());
            }
            if (withholdLog != null) {
                //如果日志存在
                return queryTradeResult(withholdLog);
            }
            //无历史记录发送代扣请求
            return sendBatTrade(orderId, managerId);
        } catch (Exception e) {
            log.error("withholding error:", e);
        }
        return Result.fail("代扣请求失败");
    }

    /**
     * 代扣请求
     * @param orderId
     * @return
     * @throws Exception
     */
    private Result sendBatTrade(Long orderId, Long managerId) throws Exception {

        Date createTime = new Date();

        final String type = "sendBatTrade";

        //查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        state(order != null, "查询不到订单");

        //查询订单代扣信息
        OrderWithhold orderWithhold = new OrderWithhold();
        orderWithhold.setOrderId(orderId);
        orderWithhold = orderWithholdMapper.selectOne(orderWithhold);
        state(orderWithhold != null, "查询不到订单代扣信息");

        //贷款金额 * 代扣点 / 100 （四舍五入）
        BigDecimal amount = order.getLoanAmount().multiply(orderWithhold.getWithholdRate())
                .divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);

        WithholdRecord withholdRecord = new WithholdRecord();
        withholdRecord.setOrderId(order.getId());
        withholdRecord.setCreateTime(createTime);
        withholdRecord.setUpdateTime(createTime);
        withholdRecord.setManagerId(managerId);
        withholdRecord.setAmount(amount);
        withholdRecordService.insert(withholdRecord);

        String uniqueKey = String.valueOf(withholdRecord.getId());

        String url = httpUrl.concat(type);

        //银行卡号
        String bankAccount = orderWithhold.getBankAccount();
        String customerName = orderWithhold.getCustomerName();
        String bankNo = orderWithhold.getBankNo();

        //企业批量包号，由企业生成订单号，必须唯一
        String corpBatNo = new SimpleDateFormat("yyyyMMddHHmmss")
                .format(new Date()).concat(uniqueKey);

        //明细列表，JSON数据格式
        List<Map<String, Object>> details = new ArrayList<>();
        Map<String, Object> map = new TreeMap<>();
        //明细序号,本批次内不重复
        map.put("listNo", 1);
        //交易金额，13位整数位+ “.” + 2位小数位
        map.put("money", amount);
        //清算行号
        map.put("bankNo", bankNo);
        //开户行号
        map.put("accBankNo", bankNo);
        //账号
        map.put("accNo", bankAccount);
        //户名
        map.put("accName", customerName);
        //附言
        map.put("atcMemo", "");
        details.add(map);

        Map<String, Object> maps = new HashMap<>();
        maps.put("corpNo", corpNo);
        maps.put("corpBatNo", corpBatNo);
        //费项代码，由通莞分配
        maps.put("feeCode", "00000");
        //业务类型， 01-代付，02-代收
        maps.put("tranCode", "02");
        //币种（CNY:人民币）
        maps.put("curType", "CNY");
        //批量或实时1：实时，0：批量,默认1
        maps.put("batFlag", "1");
        //T+N 的值,默认0
        maps.put("TN", "0");
        //总笔数
        maps.put("totalNum", "1");
        //总金额
        maps.put("totalMoney", amount.toString());
        //明细列表
        maps.put("detailList", details);
        //加密
        String sign = Cryptor.dosign(maps);
        Resource resource = new ClassPathResource(filePath);
        String filePath = resource.getFile().getPath();
        String macTag = Cryptor.sign(sign, filePath, password);
        maps.put("sign", macTag);
        String json = JSON.toJSONString(maps);
        log.info("通莞代扣,订单ID[{}],json:[{}]", orderId, json);

        //保存日志
        WithholdLog withholdLog = new WithholdLog();
        withholdLog.setOrderNo(corpBatNo);
        withholdLog.setOrderId(orderId);
        withholdLog.setRequestData(json);
        withholdLog.setCreateTime(createTime);
        withholdLog.setWithholdRecordId(withholdRecord.getId());
        withholdLogDao.insert(withholdLog);
        log.info("保存通莞代扣请求报文:[{}]", withholdLog.getId());

        String result = HttpClientUtil.httpPostWithJSON(url, json);
        state(StringUtils.hasLength(result), "通莞代扣接口连接失败...");

        log.info("通莞代扣请求回调:[{}]", result);

        WithholdLog updateWithholdLog = new WithholdLog();
        updateWithholdLog.setId(withholdLog.getId());
        updateWithholdLog.setResponseData(result);
        updateWithholdLog.setUpdateTime(new Date());
        mongoDao.update(updateWithholdLog);
        log.info("更新通莞代扣请求回调报文:[{}]", withholdLog.getId());

        //获取回调报问信息
        Map<String, Object> resultMap = JSON.parseObject(result, Map.class);
        String code = resultMap.get("code").toString();
        String message = resultMap.get("message").toString();
        Boolean status = Boolean.valueOf(resultMap.get("status").toString());

        if (!status && !Integer.valueOf("00").equals(code)) {
            //失败，更新记录状态
            withholdRecordService.updateStatus(withholdRecord.getId(), WithholdStatus.FAIL);
            return Result.fail(message);
        }

        return Result.success();
    }

    /**
     * 代扣查询
     * @param withholdLog
     * @return
     * @throws Exception
     */
    private Result queryTradeResult(WithholdLog withholdLog) throws Exception {

        final String type = "queryTradeResult";

        //请求连接
        String url = httpUrl.concat(type);
        String corpBatNo = withholdLog.getOrderNo();

        Map<String, Object> maps = new HashMap<>();
        maps.put("corpNo", corpNo);
        maps.put("corpBatNo", corpBatNo);
        String sign = Cryptor.dosign(maps);
        Resource resource = new ClassPathResource(filePath);
        String filePath = resource.getFile().getPath();
        String macTag = Cryptor.sign(sign, filePath, password);
        maps.put("sign", macTag);
        String json = JSON.toJSONString(maps);

        log.info("通莞代扣查询,流水号[{}],json:[{}]", corpBatNo, json);

        //保存日志
        WithholdQueryLog insertLog = new WithholdQueryLog();
        insertLog.setOrderNo(withholdLog.getOrderNo());
        insertLog.setOrderId(withholdLog.getOrderId());
        insertLog.setWithholdRecordId(withholdLog.getWithholdRecordId());
        insertLog.setRequestData(json);
        insertLog.setCreateTime(new Date());
        withholdQueryLogDao.insert(insertLog);
        log.info("保存通莞代扣查询报文,orderId:[{}]", withholdLog.getOrderId());

        String result = HttpClientUtil.httpPostWithJSON(url, json);
        state(StringUtils.hasLength(result), "通莞代扣接口连接失败...");

        log.info("通莞代扣查询回调,orderId:[{}],回调报文[{}]", withholdLog.getOrderId(), result);

        WithholdQueryLog updateLog = new WithholdQueryLog();
        updateLog.setId(insertLog.getId());
        updateLog.setResponseData(result);
        updateLog.setUpdateTime(new Date());
        mongoDao.update(updateLog);
        log.info("更新通莞代扣查询回调报文:[{}]", withholdLog.getId());

        //获取回调报问信息
        Map<String, Object> resultMap = JSON.parseObject(result, Map.class);
        boolean ok = (Boolean) resultMap.get("status");
        String message = resultMap.get("message").toString();
        if (!ok) {
            return Result.fail(message);
        }
        String data = resultMap.get("data").toString();
        Map<String, Object> dataMap = JSON.parseObject(data, Map.class);

        String status = dataMap.get("pstatus").toString();
        if ("30".equals(status)) {
            //状态为已拒绝
            withholdRecordService.updateStatus(withholdLog.getWithholdRecordId(), WithholdStatus.FAIL);
            return Result.fail("查询成功,交易已拒绝。");
        }
        if ("20".equals(status)) {
            //代扣成功
            withholdRecordService.updateStatus(withholdLog.getWithholdRecordId(), WithholdStatus.SUCCESS);
            return Result.success();
        }

        return Result.fail("查询成功,交易正在处理中。");
    }
}
